package com.ytktt.study.week3.task2;

import com.ytktt.study.week3.task2.netty.HttpHandler;
import com.ytktt.study.week3.task2.netty.HttpInitializer;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.epoll.EpollChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

/**
 * netty 客户端
 *
 * @author ytk
 */
public class NettyHttpClient {

    private NettyHttpClient() {}

    private static class NettyHttpClientHolder {
        private static final NettyHttpClient HOLDER = new NettyHttpClient();
    }

    public static NettyHttpClient getInstance() {
        return NettyHttpClientHolder.HOLDER;
    }

    public String get(String url) throws Exception {
        NioEventLoopGroup group = new NioEventLoopGroup();
        NettyClientHandler handler = new NettyClientHandler();
        try {
            Bootstrap b = new Bootstrap();
            b.option(ChannelOption.SO_BACKLOG, 128)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .option(ChannelOption.SO_REUSEADDR, true)
                    .option(ChannelOption.SO_RCVBUF, 32 * 1024)
                    .option(ChannelOption.SO_SNDBUF, 32 * 1024)
                    .option(EpollChannelOption.SO_REUSEPORT, true)
                    .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);

            b.group(group).channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new HttpClientCodec());
                            p.addLast(new HttpObjectAggregator(1024 * 1024));
                            p.addLast(new LoggingHandler(LogLevel.INFO));
                            p.addLast(handler);
                        }
                    });

            // TODO: 正常需要在入口做下检查
            String host = url.substring(0, url.lastIndexOf(":"));
            int port = Integer.parseInt(url.substring(url.lastIndexOf(":") + 1));
            ChannelFuture channelFuture = b.connect(host, port).sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }

        return handler.getResult();
    }
}
